package com.lh.interceptor;

import com.lh.util.MyLog;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;

/**
 * @Author LuoHang
 * @Date 2022-05-10 19:52
 **/
public class LoginInterceptor implements HandlerInterceptor {
    private Long startTime;

    /**
     * preHandle叫做预处理方法
     * 参数：
     * @param request 请求
     * @param response 响应
     * @param handler 被拦截的控制器对象 Controller对象
     * @return boolean true 请求通过了拦截器的验证，可以执行处理器的方法（AOP目标方法）
     *                      执行顺序：MyInterceptor拦截器的preHandle()方法执行.......
     *                              UserController的控制器方法doSome()执行
     *                              MyInterceptor拦截器的postHandle()方法执行.......
     *                              MyInterceptor拦截器的afterCompletion()方法执行.......
     *                 false 请求没有通过拦截器的验证，请求到拦截器截至了，请求没有被处理
     * @throws Exception 异常
     *
     * 特点：
     * 1.方法在控制器方法之前执行的。用户的请求首先到达此方法
     * 2，在这个方法中可以获取请求的信息，验证请求是否符合要求。
     * 可以验证用户是否登录，验证用户是否有某个连接地址的访问权限
     * 如果验证失败，可以截断请求，请求不能被处理
     * 如果验证成功，可以放行，此时控制器方法才能执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        this.startTime = System.currentTimeMillis();
        MyLog.info(LoginInterceptor.class,"LoginInterceptor拦截器的preHandle()方法执行.......");
        request.setAttribute("test","test");

        //测试拦截器预处理方法获取前台传入的所有参数
        Map<String, String[]> map = request.getParameterMap();
        Set<Map.Entry<String, String[]>> entries = map.entrySet();
        for (Map.Entry<String, String[]> entry : entries) {
            //想通过getParameterMap改变前端传送的值，报错java.lang.IllegalStateException：
            //No modifications are allowed to a locked ParameterMap
            //if<"uid".equals(entry.getKey()-->map.put("uid",new String[]{String.valueOf(2)})
            MyLog.info(LoginInterceptor.class,"request params[" + entry.getKey()+"]="
                    + Arrays.toString(entry.getValue()));
        }
        //给浏览器一个结果
        HttpSession session = request.getSession();
        Object obj = session.getAttribute("curUser");
        if (obj == null){
            request.setAttribute("msg","请先登录！！！！！");
            //"/user/error"
            //"/"返回到首页
            request.getRequestDispatcher("/").forward(request,response);
            return false;
        }
        return true;
    }

    /**
     * postHandle：后处理方法(当发生Controller层发生异常时，此方法是不会被被触发的)
     * @param request 请求
     * @param response 响应
     * @param handler 被拦截的控制器对象 Controller对象
     * @param modelAndView 处理器方法的返回值
     *
     * 特点：
     * 1.在处理器方法（UserController.doSome()）执行后执行
     * 2.能够获取到处理器方法的返回值ModelAndView，可以修改ModelAndView中的数据和视图，可以影响到最后的执行结果
     * 3.主要是对原来的执行结果进行二次修正
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        MyLog.info(LoginInterceptor.class,"LoginInterceptor拦截器的postHandle()方法执行.......");
        if (modelAndView != null){
            modelAndView.addObject("msg","拦截器中添加的数据");
        }
    }

    /**
     * afterCompletion：最后执行的方法
     * @param request 请求
     * @param response 响应
     * @param handler 被拦截的控制器对象
     * @param ex 程序中发生的异常
     *
     * 特点：
     * 1.在请求处理完成后执行的。框架中规定是当你的视图处理完成后，对视图执行了forward，就认为请求处理完成，
     * 2.一般做资源回收工作，程序请求过程中创建了一些对象，在这里可以删除，把占用的内存回收。
     **/
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        MyLog.info(LoginInterceptor.class,"LoginInterceptor拦截器的afterCompletion()方法执行.......");
        long time = System.currentTimeMillis()-startTime;
        MyLog.info(LoginInterceptor.class,"请求花费时间：" + time);
        //handler=org.springframework.web.method.HandlerMethod
        MyLog.info(LoginInterceptor.class,"handler=" + handler.getClass().getName());
        //exception
        MyLog.info(LoginInterceptor.class,"exception" + ((ex != null)?ex.getMessage():""));
    }
}
